package com.jackstraw.jack_base.util.entity;


import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.jackstraw.jack_base.util.ObjectUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

@Data
@Slf4j
public class BaseEntity<T> implements Serializable {

    /**
     * 序列化号
     */
    private static final long serialVersionUID = 7231021186278058888L;

    /**
     * 拿到对应的实体类对象
     */
    @JsonIgnore
    @JSONField(serialize = false, deserialize = false)
    private transient Class<?> entityClass;

    /**
     * 默认从下标为0的获取泛型
     *
     * @return
     */
    public Class<?> getEntityClass() {
        if (ObjectUtil.ObjectUtilByLang3.isEmpty(this.entityClass)) {
            synchronized (this) {
                this.entityClass = this.getEntityClass(0);
            }
        }
        return this.entityClass;
    }


    public Class<?> getEntityClass(Integer index) {
        return this.currentModelClass(index);
    }

    /**
     * 解析
     *
     * @return
     */
    protected Class<?> currentModelClass(Integer index) {
        return this.getSuperClassGenericType(getClass(), index);
    }


    /**
     * <p>
     * 反射对象获取泛型
     * </p>
     *
     * @param clazz 对象
     * @param index 泛型所在位置
     * @return Class
     */
    public static Class<?> getSuperClassGenericType(Class<?> clazz, int index) {
        Type genType = clazz.getGenericSuperclass();
        if (ParameterizedType.class.isAssignableFrom(genType.getClass())) {
            Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
            if (index <= params.length && index >= 0) {
                if ((params[index] instanceof Class)) {
                    return (Class) params[index];
                } else if (ParameterizedType.class.isAssignableFrom(params[index].getClass())) {
                    ParameterizedType parameterizedType = (ParameterizedType) params[index];
                    Type rawType = parameterizedType.getRawType();
                    if ((rawType instanceof Class)) {
                        return (Class) rawType;
                    }
                }
                log.warn(String.format("Warn: %s not set the actual class on superclass generic parameter", clazz.getSimpleName()));
                return Object.class;
            } else {
                log.warn(String.format("Warn: Index: %s, Size of %s's Parameterized Type: %s .", index, clazz.getSimpleName(), params.length));
                return Object.class;
            }
        } else if (genType instanceof Class) {
            return getSuperClassGenericType(((Class<?>) genType), index);
        }
        log.warn(String.format("Warn: %s's superclass not ParameterizedType", clazz.getSimpleName()));
        return Object.class;
    }

    /**
     * 创建泛型对应的对象
     *
     * @param initargs
     * @return
     */
    public <M> M newInstance(Object... initargs) {
        return this.newInstance(0, initargs);
    }

    /**
     * 创建泛型对应的对象
     *
     * @param initargs
     * @return
     */
    public <M> M newInstance(Integer index, Object... initargs) {
        Constructor<M> declaredConstructor = null;
        M m = null;
        try {
            declaredConstructor = ((Class<M>) this.getEntityClass(index)).getDeclaredConstructor();
            m = declaredConstructor.newInstance(initargs);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return m;
    }
}
